﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using System.Windows.Forms;
using System.Threading.Tasks;

namespace BoringTodo
{
    // DataManager.cs
    public class DataManager
    {
        private readonly string folderPath;
        private readonly string backupFolderPath;
        private const int MAX_BACKUP_FILES = 100;

        public DataManager(string myDocumentsPath)
        {
            folderPath = Path.Combine(myDocumentsPath, Constants.AppDataFolder);
            backupFolderPath = Path.Combine(folderPath, "备份");

            try
            {
                // 使用同步方法确保目录存在，因为这是构造函数
                EnsureDirectoriesExist();
            }
            catch (Exception ex)
            {
                Logger.LogError("初始化数据文件夹失败", ex);
                throw; // 重新抛出异常，因为如果文件夹创建失败，应用程序无法正常工作
            }
        }

        private void EnsureDirectoriesExist()
        {
            try
            {
                // 确保主文件夹存在
                if (!Directory.Exists(folderPath))
                {
                    // 尝试创建带有完全控制权限的目录
                    Directory.CreateDirectory(folderPath);
                    
                    // 确保目录有写入权限（以防系统设置了限制）
                    File.SetAttributes(folderPath, FileAttributes.Normal | FileAttributes.Directory);
                    
                    Logger.Log($"创建数据文件夹: {folderPath}", LogLevel.Info);
                }
                
                // 确保备份文件夹存在
                if (!Directory.Exists(backupFolderPath))
                {
                    Directory.CreateDirectory(backupFolderPath);
                    File.SetAttributes(backupFolderPath, FileAttributes.Normal | FileAttributes.Directory);
                    Logger.Log($"创建备份文件夹: {backupFolderPath}", LogLevel.Info);
                }
            }
            catch (UnauthorizedAccessException uaEx)
            {
                string errorMsg = $"无权限创建目录。请确保应用程序有足够的权限访问: {folderPath}";
                Logger.LogError(errorMsg, uaEx);
                MessageBox.Show(errorMsg + "\n\n具体错误: " + uaEx.Message, 
                    "权限错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                throw; // 重新抛出异常，因为如果目录无法创建，应用程序无法正常工作
            }
            catch (Exception ex)
            {
                string errorMsg = $"创建应用程序目录时发生错误: {ex.Message}";
                Logger.LogError(errorMsg, ex);
                MessageBox.Show(errorMsg, "目录错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                throw; // 重新抛出异常，因为如果目录无法创建，应用程序无法正常工作
            }
        }

        private async Task CreateBackupAsync(string fileName, string jsonData)
        {
            try
            {
                // 生成备份文件名（原文件名_时间戳.json）
                string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                string backupFileName = Path.GetFileNameWithoutExtension(fileName) + 
                                      "_" + timestamp + 
                                      Path.GetExtension(fileName);
                string backupFilePath = Path.Combine(backupFolderPath, backupFileName);

                // 保存备份文件
                await FileUtils.WriteAllTextAsync(backupFilePath, jsonData);
                Logger.Log($"创建备份文件: {backupFileName}", LogLevel.Info);

                // 检查并清理旧备份
                await CleanupOldBackupsAsync();
            }
            catch (Exception ex)
            {
                Logger.LogError($"创建备份失败: {fileName}", ex);
                MessageBox.Show($"创建备份时发生错误: {ex.Message}", "备份错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private async Task CleanupOldBackupsAsync()
        {
            try
            {
                // 获取所有备份文件并按创建时间排序
                var backupFiles = Directory.GetFiles(backupFolderPath, "*.json")
                                         .Select(f => new FileInfo(f))
                                         .OrderByDescending(f => f.CreationTime)
                                         .ToList();

                // 如果备份文件数量超过限制，删除最旧的文件
                if (backupFiles.Count > MAX_BACKUP_FILES)
                {
                    int filesToDelete = backupFiles.Count - MAX_BACKUP_FILES;
                    Logger.Log($"清理旧备份文件 ({filesToDelete} 个文件)", LogLevel.Info);
                    
                    var oldestFiles = backupFiles.Skip(MAX_BACKUP_FILES).ToList();
                    
                    foreach (var file in oldestFiles)
                    {
                        try
                        {
                            // 使用FileUtils异步删除文件
                            await FileUtils.DeleteFileAsync(file.FullName);
                            Logger.Log($"已删除旧备份文件: {file.Name}", LogLevel.Info);
                        }
                        catch (UnauthorizedAccessException uaEx)
                        {
                            // 记录文件权限错误但继续处理其他文件
                            Logger.LogError($"无权限删除备份文件: {file.Name}", uaEx);
                            
                            // 尝试使用设置文件属性的方式删除
                            try 
                            {
                                if (File.Exists(file.FullName))
                                {
                                    // 移除只读属性然后尝试删除
                                    File.SetAttributes(file.FullName, FileAttributes.Normal);
                                    await FileUtils.DeleteFileAsync(file.FullName);
                                    Logger.Log($"移除只读属性后删除文件成功: {file.Name}", LogLevel.Info);
                                }
                            }
                            catch (Exception deepEx)
                            {
                                Logger.LogError($"二次尝试删除文件仍然失败: {file.Name}", deepEx);
                            }
                        }
                        catch (Exception ex)
                        {
                            // 记录其他类型的错误但继续处理剩余文件
                            Logger.LogError($"删除备份文件时发生错误: {file.Name}", ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogError("清理旧备份失败", ex);
                MessageBox.Show($"清理旧备份时发生错误: {ex.Message}", "清理错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        public BindingList<TodoItem> LoadData(string fileName)
        {
            string filePath = Path.Combine(folderPath, fileName);

            try
            {
                if (!File.Exists(filePath))
                {
                    // 如果文件不存在，创建一个空文件
                    File.WriteAllText(filePath, JsonConvert.SerializeObject(new List<TodoItem>()));
                    Logger.Log($"创建新数据文件: {fileName}", LogLevel.Info);
                }

                string jsonData = File.ReadAllText(filePath);
                List<TodoItem> items = JsonConvert.DeserializeObject<List<TodoItem>>(jsonData) ?? new List<TodoItem>();
                Logger.Log($"加载数据文件: {fileName}, 项目数: {items.Count}", LogLevel.Info);
                return new BindingList<TodoItem>(items);
            }
            catch (JsonException ex)
            {
                Logger.LogError($"JSON解析错误: {fileName}", ex);
                MessageBox.Show($"数据文件 {fileName} 格式错误: {ex.Message}\n将创建一个新的空文件。", "加载错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return new BindingList<TodoItem>();
            }
            catch (Exception ex)
            {
                Logger.LogError($"加载数据失败: {fileName}", ex);
                MessageBox.Show($"加载数据时发生错误: {ex.Message}", "加载错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return new BindingList<TodoItem>();
            }
        }

        public void SaveData(string fileName, BindingList<TodoItem> todoList)
        {
            string filePath = Path.Combine(folderPath, fileName);

            try
            {
                string jsonData = JsonConvert.SerializeObject(todoList, Formatting.Indented);
                
                // 先创建备份
                CreateBackupAsync(fileName, jsonData).ConfigureAwait(false);

                // 然后保存新数据
                File.WriteAllText(filePath, jsonData);
                
                Logger.Log($"保存数据文件: {fileName}, 项目数: {todoList.Count}", LogLevel.Info);
            }
            catch (Exception ex)
            {
                Logger.LogError($"保存数据失败: {fileName}", ex);
                MessageBox.Show($"保存数据时发生错误: {ex.Message}", "保存错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public async Task<BindingList<TodoItem>> LoadDataAsync(string fileName)
        {
            string filePath = Path.Combine(folderPath, fileName);

            try
            {
                if (!File.Exists(filePath))
                {
                    // 如果原始文件不存在，尝试从备份文件恢复
                    await TryRecoverFromLatestBackupAsync(fileName);
                    
                    // 再次检查文件是否存在，如果仍然不存在，则创建空文件
                    if (!File.Exists(filePath))
                    {
                        await FileUtils.WriteAllTextAsync(filePath, JsonConvert.SerializeObject(new List<TodoItem>()));
                        Logger.Log($"创建新数据文件: {fileName}", LogLevel.Info);
                    }
                }

                // 使用文件锁定避免读写冲突
                using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                using (var reader = new StreamReader(fileStream))
                {
                    string jsonData = await reader.ReadToEndAsync();
                    
                    // 使用线程池线程进行JSON反序列化，避免阻塞UI线程
                    var items = await Task.Run(() => 
                        JsonConvert.DeserializeObject<List<TodoItem>>(jsonData) ?? new List<TodoItem>());
                    
                    Logger.Log($"异步加载数据文件: {fileName}, 项目数: {items.Count}", LogLevel.Info);
                    return new BindingList<TodoItem>(items);
                }
            }
            catch (JsonException ex)
            {
                Logger.LogError($"JSON解析错误: {fileName}", ex);
                
                // 尝试从最新备份恢复
                bool recovered = await TryRecoverFromLatestBackupAsync(fileName);
                if (recovered) 
                {
                    // 如果成功恢复，重新尝试加载
                    return await LoadDataAsync(fileName);
                }
                
                MessageBox.Show($"数据文件 {fileName} 格式错误: {ex.Message}\n将创建一个新的空文件。", "加载错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return new BindingList<TodoItem>();
            }
            catch (Exception ex)
            {
                Logger.LogError($"异步加载数据失败: {fileName}", ex);
                MessageBox.Show($"加载数据时发生错误: {ex.Message}", "加载错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return new BindingList<TodoItem>();
            }
        }

        public async Task SaveDataAsync(string fileName, BindingList<TodoItem> todoList)
        {
            string filePath = Path.Combine(folderPath, fileName);

            try
            {
                // 创建临时文件
                string tempFilePath = Path.Combine(folderPath, Path.GetRandomFileName() + ".tmp");
                
                // 使用线程池线程序列化JSON，避免阻塞UI线程
                string jsonData = await Task.Run(() => 
                    JsonConvert.SerializeObject(todoList, Formatting.Indented));
                
                // 创建备份
                await CreateBackupAsync(fileName, jsonData);
                
                // 先写入临时文件
                await FileUtils.WriteAllTextAsync(tempFilePath, jsonData);
                
                // 使用事务性文件操作替换目标文件
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                File.Move(tempFilePath, filePath);
                
                Logger.Log($"异步保存数据文件: {fileName}, 项目数: {todoList.Count}", LogLevel.Info);
            }
            catch (Exception ex)
            {
                Logger.LogError($"异步保存数据失败: {fileName}", ex);
                MessageBox.Show($"保存数据时发生错误: {ex.Message}", "保存错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        // 尝试从最新备份恢复数据文件
        private async Task<bool> TryRecoverFromLatestBackupAsync(string fileName)
        {
            try
            {
                var backupFiles = Directory.GetFiles(backupFolderPath, 
                    Path.GetFileNameWithoutExtension(fileName) + "_*.json")
                    .OrderByDescending(f => File.GetLastWriteTime(f))
                    .ToList();
                
                if (backupFiles.Count == 0)
                {
                    Logger.Log($"没有找到备份文件: {fileName}", LogLevel.Warning);
                    return false;
                }
                
                string latestBackup = backupFiles[0];
                string targetPath = Path.Combine(folderPath, fileName);
                
                // 复制最新备份到主数据文件
                File.Copy(latestBackup, targetPath, true);
                
                Logger.Log($"从备份恢复数据文件: {Path.GetFileName(latestBackup)} -> {fileName}", LogLevel.Info);
                return true;
            }
            catch (Exception ex)
            {
                Logger.LogError($"从备份恢复失败: {fileName}", ex);
                return false;
            }
        }
        
        public async Task<bool> ExportDataAsync(string fileName, string exportPath)
        {
            try
            {
                string sourcePath = Path.Combine(folderPath, fileName);
                
                if (!File.Exists(sourcePath))
                {
                    MessageBox.Show($"要导出的文件不存在: {fileName}", "导出错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
                
                await FileUtils.CopyAsync(sourcePath, exportPath);
                Logger.Log($"导出数据: {fileName} -> {exportPath}", LogLevel.Info);
                return true;
            }
            catch (Exception ex)
            {
                Logger.LogError($"导出数据失败: {fileName}", ex);
                MessageBox.Show($"导出数据时发生错误: {ex.Message}", "导出错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }
        
        public async Task<bool> ImportDataAsync(string importPath, string fileName)
        {
            try
            {
                if (!File.Exists(importPath))
                {
                    return false;
                }

                string jsonData = await FileUtils.ReadAllTextAsync(importPath);
                string targetPath = Path.Combine(folderPath, fileName);
                
                // 创建备份
                if (File.Exists(targetPath))
                {
                    await CreateBackupAsync(fileName, await FileUtils.ReadAllTextAsync(targetPath));
                }

                await FileUtils.WriteAllTextAsync(targetPath, jsonData);
                return true;
            }
            catch (Exception ex)
            {
                Logger.LogError($"导入数据失败: {importPath} -> {fileName}", ex);
                return false;
            }
        }
        
        // 获取数据文件的完整路径
        public string GetDataFilePath(string fileName)
        {
            return Path.Combine(folderPath, fileName);
        }
        
        // 获取所有可能的数据存储位置
        public List<string> GetPossibleDataPaths(string fileName)
        {
            return new List<string>
            {
                // 标准位置 - 用户文档目录
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 
                    Constants.AppDataFolder, fileName),
                
                // 备用位置 - 应用程序目录
                Path.Combine(Application.StartupPath, fileName),
                
                // 数据子目录 - 用户文档
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 
                    Constants.AppDataFolder, "Data", fileName),
                
                // 数据子目录 - 应用程序目录
                Path.Combine(Application.StartupPath, "Data", fileName)
            };
        }
    }
}
